package com.mokairui.share_model__routines.protective_pause.extension;

import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author Mokairui
 * @Since 2021/7/31
 */
@Slf4j(topic = "c.ProtectivePauseExtension")
public class ProtectivePauseExtension {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            // 生产信件
            new People().start();
        }
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Mailboxes.getIds());
        for (Integer id : Mailboxes.getIds()) {
            new Postman(id, String.format("内容 id: %s", id)).start();
        }
    }
}

@Slf4j(topic = "c.people")
class People extends Thread {
    @Override
    public void run() {
        // 产出信件
        GuardedObject guardedObject = Mailboxes.createGuardedObject();
        log.debug("开始收信 id:{}", guardedObject.getId());
        // 设置5s超时时间 获取信件信息
        String mail = (String) guardedObject.get(5000);
        log.debug("收到信 id:{}, 内容：{}", guardedObject.getId(), mail);
    }
}

@Slf4j(topic = "c.postman")
class Postman extends Thread {
    private int id;
    private String mail;

    public Postman(int id, String mail) {
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
        // 根据信件id送信件, 每次送出去就从集合删除
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        log.debug("送信 id:{}, 内容: {}", id, mail);
        // 将内容送到信件盒子中
        guardedObject.complete(mail);
    }
}

class Mailboxes {
    private static Map<Integer, GuardedObject> boxes = new ConcurrentHashMap<>();

    private static int id = 1;

    private static synchronized int generatedId() {
        return id ++;
    }

    // 创建信件
    public static GuardedObject createGuardedObject() {
        GuardedObject guardedObject = new GuardedObject(generatedId());
        // 将信件的id 和 信件对象存入concurrentHashMap中
        boxes.put(guardedObject.getId(), guardedObject);
        return guardedObject;
    }

    public static GuardedObject getGuardedObject(int id) {
        return boxes.remove(id);
    }

    public static Set<Integer> getIds() {
        return boxes.keySet();
    }

}

// 增强超时效果
class GuardedObject {
    // 标识 Guarded Object
    private int id;
    private Object response;

    public GuardedObject(int generatedId) {
        this.id = generatedId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Object get(long timeout) {
        synchronized (this) {
            while (response == null) {
                long begin = System.currentTimeMillis();
                long passTime = 0;
                try {
                    long waitTime = timeout - passTime;
                    if (waitTime < 0) {
                        break;
                    }
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passTime = System.currentTimeMillis() - begin;
            }
            return this.response;
        }
    }

    public void complete(Object object) {
        synchronized (this) {
            this.response = object;
            this.notifyAll();
        }
    }
}
